pub mod config;
pub mod models;

use axum::{
    body::{Body, to_bytes},
    extract::{Request, State},
    http::StatusCode,
    middleware::Next,
    response::{Response, IntoResponse},
    routing::get,
    Router,
    Json,
};
use std::{net::SocketAddr, sync::Arc, fs::OpenOptions, io::Write, path::Path, time::Duration};
use tokio::sync::Mutex;
use chrono::Utc;
use tracing::{info, warn, debug};
use serde_json::json;

use crate::{config::Config, models::RequestLog};

// 设置内存中保留的最大日志数量（减少最大日志数量）
const MAX_IN_MEMORY_LOGS: usize = 500;
// 设置日志最大保留时间（分钟）
const MAX_LOG_AGE_MINUTES: i64 = 30;

pub fn create_app(config: Config, state: Arc<Mutex<Vec<RequestLog>>>) -> Router {
    // 启动定期清理任务
    start_cleanup_task(state.clone());
    
    // 记录所有路由信息
    let mut route_info = Vec::new();
    
    let mut app = Router::new()
        .route("/logs", get(get_logs))
        .with_state(state.clone());
    
    // 记录 /logs 路由
    route_info.push(("GET", "/logs".to_string()));

    // 为每个配置的端点添加路由
    for endpoint in &config.endpoints {
        let path = endpoint.path.clone();
        app = app.route(&path, get(handle_request).post(handle_request));
        
        // 记录路由信息
        route_info.push(("GET", path.clone()));
        route_info.push(("POST", path.clone()));
    }

    // 打印路由信息
    print_routes(&route_info);

    // 添加日志中间件
    app.layer(axum::middleware::from_fn_with_state(state, log_request))
}

// 打印路由信息，类似 Rocket 的格式
fn print_routes(routes: &[(&str, String)]) {
    println!("\n🚀 已配置的路由:");
    println!("┌──────────┬──────────────────────────────────────────────────");
    println!("│ 请求方法 │ 路径");
    println!("├──────────┼──────────────────────────────────────────────────");
    
    for (method, path) in routes {
        println!("│ {:<8} │ {}", method, path);
    }
    
    println!("└──────────┴──────────────────────────────────────────────────\n");
}

async fn log_request(
    State(state): State<Arc<Mutex<Vec<RequestLog>>>>,
    request: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    // 获取当前时间
    let now = Utc::now();
    let timestamp = now.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
    
    let method = request.method().clone();
    let uri = request.uri().clone();
    let path = uri.path();
    let headers = request.headers().clone();
    let remote_addr = request
        .extensions()
        .get::<axum::extract::ConnectInfo<SocketAddr>>()
        .map(|addr| addr.0.to_string())
        .unwrap_or_default();

    // 获取请求体
    let (parts, body) = request.into_parts();
    let bytes = to_bytes(body, 20 * 1024 * 1024).await.map_err(|_| StatusCode::BAD_REQUEST)?;
    let body_str = String::from_utf8_lossy(&bytes).to_string();

    // 创建新的请求
    let request = Request::from_parts(parts, Body::from(bytes));

    // 检查是否为错误请求路径，为这些请求使用简化的日志记录方式
    let is_error_path = path.contains("unauthorized") || path.contains("auth") || 
                        path.contains("notfound") || path.contains("forbidden") || 
                        path.contains("server_error") || path.contains("bad_request");

    // 处理 JSON 请求体，只对非错误路径的请求保存完整JSON
    let json_file_path = if !is_error_path && is_json_content(&headers) {
        match save_json_body(&body_str) {
            Ok(path) => Some(path),
            Err(e) => {
                warn!("Failed to save JSON body: {}", e);
                None
            }
        }
    } else {
        None
    };

    // 记录请求日志，对于错误路径的请求，不存储完整的请求体
    let log = if is_error_path {
        // 对错误路径请求，只存储摘要信息
        let  simplified_log = RequestLog::new(
            method.clone(),
            uri.clone(),
            headers.clone(),
            // 只保留请求体摘要
            if body_str.len() > 100 { format!("{}...(已省略)", &body_str[..100]) } else { body_str.clone() },
            remote_addr.clone(),
            None, // 不保存JSON文件
        );
        simplified_log
    } else {
        // 对正常请求，存储完整信息
        RequestLog::new(
            method.clone(),
            uri.clone(),
            headers.clone(),
            body_str.clone(),
            remote_addr.clone(),
            json_file_path.clone(),
        )
    };
    
    // 将日志添加到内存中，并限制大小
    let log_cleaned = {
        let mut logs = state.lock().await;
        logs.push(log.clone());
        
        // 清理过期的日志
        let now = Utc::now();
        let mut cleaned = false;
        
        // 1. 基于时间的清理 - 清除超过最大保留时间的日志
        let logs_before = logs.len();
        logs.retain(|log| {
            (now - log.timestamp).num_minutes() < MAX_LOG_AGE_MINUTES
        });
        
        if logs.len() < logs_before {
            cleaned = true;
        }
        
        // 2. 基于数量的清理 - 如果超过最大限制，则删除最旧的日志
        if logs.len() > MAX_IN_MEMORY_LOGS {
            // 保留最新的日志，删除旧日志
            let start_index = logs.len() - MAX_IN_MEMORY_LOGS;
            *logs = logs.drain(start_index..).collect();
            cleaned = true;
        }
        
        // 手动触发额外的内存回收
        if cleaned {
            std::mem::drop(logs.drain(..0));
        }
        
        cleaned
    };
    
    // 锁释放后再打印日志
    if log_cleaned {
        info!("已清理日志，当前内存中保留 {} 条日志", 
            state.lock().await.len());
    }
    
    // 使用 tracing 记录请求日志到控制台和日志文件
    let body_preview = if body_str.len() > 50 {
        format!("{}...", &body_str[..50])
    } else {
        body_str.clone()
    };
    
    // 打印美化的请求信息到控制台
    info!(
        target: "request",
        "\n============================ 请求详情 ============================\n\
        时间: {}\n\
        方法: {}\n\
        路径: {}\n\
        来源: {}\n\
        请求体: {}\n\
        =================================================================",
        timestamp,
        method,
        uri,
        remote_addr,
        body_preview
    );
    
    // 详细日志记录
    debug!(
        method = %method,
        uri = %uri,
        remote_addr = %remote_addr,
        body = %body_str,
        json_file = ?json_file_path,
        "请求详情"
    );

    // 继续处理请求
    let response = next.run(request).await;
    
    // 记录响应信息
    info!(
        target: "response",
        "响应状态: {}", 
        response.status()
    );
    
    Ok(response)
}

fn is_json_content(headers: &axum::http::HeaderMap) -> bool {
    headers
        .get("content-type")
        .and_then(|value| value.to_str().ok())
        .map(|content_type| content_type.contains("application/json"))
        .unwrap_or(false)
}

// 优化 JSON 文件存储：添加清理旧文件的功能
fn save_json_body(body: &str) -> std::io::Result<String> {
    // 创建 json_bodies 目录（如果不存在）
    let json_dir = Path::new("json_bodies");
    if !json_dir.exists() {
        std::fs::create_dir(json_dir)?;
    }

    // 生成文件名（使用时间戳）
    let timestamp = Utc::now().format("%Y%m%d_%H%M%S_%f");
    let filename = format!("json_bodies/request_{}.json", timestamp);
    
    // 保存 JSON 文件
    let mut file = OpenOptions::new()
        .create(true)
        .write(true)
        .open(&filename)?;
    
    writeln!(file, "{}", body)?;
    
    // 定期清理旧文件（保留最近1000个文件）
    if timestamp.to_string().ends_with("000") { // 每隔一段时间执行清理
        match clean_old_json_files(1000) {
            Ok(count) => if count > 0 { info!("已清理 {} 个旧的 JSON 文件", count); },
            Err(e) => warn!("清理旧 JSON 文件失败: {}", e),
        }
    }
    
    Ok(filename)
}

// 清理旧的 JSON 文件，保留最新的 keep_count 个文件
fn clean_old_json_files(keep_count: usize) -> std::io::Result<usize> {
    let json_dir = Path::new("json_bodies");
    if !json_dir.exists() {
        return Ok(0);
    }
    
    // 获取所有JSON文件并按修改时间排序
    let mut files: Vec<_> = std::fs::read_dir(json_dir)?
        .filter_map(Result::ok)
        .filter(|entry| {
            if let Ok(file_type) = entry.file_type() {
                file_type.is_file() && entry.path().extension().map_or(false, |ext| ext == "json")
            } else {
                false
            }
        })
        .collect();
    
    // 按修改时间排序（从旧到新）
    files.sort_by_key(|entry| {
        entry.metadata().ok().and_then(|m| m.modified().ok()).unwrap_or_else(|| 
            std::time::SystemTime::UNIX_EPOCH)
    });
    
    // 如果文件数量超过保留数量，删除最旧的文件
    let delete_count = if files.len() > keep_count {
        files.len() - keep_count
    } else {
        0
    };
    
    // 删除旧文件
    for i in 0..delete_count {
        if let Err(e) = std::fs::remove_file(files[i].path()) {
            warn!("删除文件 {:?} 失败: {}", files[i].path(), e);
        }
    }
    
    Ok(delete_count)
}

async fn handle_request(request: Request) -> impl IntoResponse {
    // 根据请求路径决定是否返回错误
    let path = request.uri().path();
    
    // 检查路径是否需要返回401错误
    if path.contains("unauthorized") || path.contains("auth") {
        return (
            StatusCode::UNAUTHORIZED,
            Json(json!({
                "error": "未授权访问",
                "message": "请提供有效的认证信息"
            }))
        );
    }
    
    // 检查路径是否需要返回其他错误码
    if path.contains("notfound") {
        return (
            StatusCode::NOT_FOUND,
            Json(json!({
                "error": "资源未找到",
                "message": "请求的资源不存在"
            }))
        );
    }
    
    if path.contains("forbidden") {
        return (
            StatusCode::FORBIDDEN,
            Json(json!({
                "error": "禁止访问",
                "message": "您没有权限访问此资源"
            }))
        );
    }
    
    if path.contains("server_error") {
        return (
            StatusCode::INTERNAL_SERVER_ERROR,
            Json(json!({
                "error": "服务器错误",
                "message": "服务器内部错误"
            }))
        );
    }
    
    if path.contains("bad_request") {
        return (
            StatusCode::BAD_REQUEST,
            Json(json!({
                "error": "请求无效",
                "message": "请求参数无效或格式不正确"
            }))
        );
    }

    // 默认返回成功响应
    (
        StatusCode::OK,
        Json(json!({
            "message": "请求已接收并记录",
            "status": "success"
        }))
    )
}

async fn get_logs(State(state): State<Arc<Mutex<Vec<RequestLog>>>>) -> String {
    let logs = state.lock().await;
    serde_json::to_string_pretty(&*logs).unwrap_or_default()
}

// 启动定期清理任务
fn start_cleanup_task(state: Arc<Mutex<Vec<RequestLog>>>) {
    tokio::spawn(async move {
        let mut interval = tokio::time::interval(Duration::from_secs(60)); // 每分钟运行一次
        loop {
            interval.tick().await;
            
            let cleaned = {
                let mut logs = state.lock().await;
                if logs.is_empty() {
                    false
                } else {
                    let now = Utc::now();
                    let before_count = logs.len();
                    
                    // 基于时间清理
                    logs.retain(|log| {
                        (now - log.timestamp).num_minutes() < MAX_LOG_AGE_MINUTES
                    });
                    
                    // 基于数量清理
                    if logs.len() > MAX_IN_MEMORY_LOGS {
                        let start_index = logs.len() - MAX_IN_MEMORY_LOGS;
                        *logs = logs.drain(start_index..).collect();
                    }
                    
                    // 手动触发额外的内存回收
                    std::mem::drop(logs.drain(..0));
                    
                    before_count > logs.len()
                }
            };
            
            if cleaned {
                info!("定期清理：已删除过期日志，当前内存中保留 {} 条日志", 
                    state.lock().await.len());
            }
        }
    });
}